package pe.edu.upc.e41a.javasoft.daoImpl;

import java.util.List;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import pe.edu.upc.e41a.javasoft.dao.CategoriaDao;
import pe.edu.upc.e41a.javasoft.domain.Categoria;
import pe.edu.upc.e41a.javasoft.domain.Publicacion;

@Repository(value = "CategoriaDao")
public class CategoriaDaoImpl implements CategoriaDao {

	
	private static final Log log = LogFactory.getLog(AvisoDaoImpl.class);

	@PersistenceContext
	transient EntityManager em;

	public final EntityManager entityManager() {
		EntityManager entityManager = em;
		if (entityManager == null)
			throw new IllegalStateException(
					"Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
		return entityManager;
	}

	//Métodos persistentes
	
	@Transactional
	@Override
	public void saveCategoria(Categoria categoria) {
		if (em == null)
			this.em = this.em;
		em.persist(categoria);
	}

	@Transactional
	@Override
	public void updateCategoria(Categoria categoria) {
		if (em == null)
			this.em = this.em;
		em.merge(categoria);
		em.flush();
	}

	@Transactional
	@Override
	public void deleteCategoria(Categoria categoria) {
		if (em == null)
			this.em = this.em;
		if (em.contains(categoria)) {
			em.remove(categoria);
		} else {
			Categoria attached = this.findCategoria(categoria.getCodigo());
			em.remove(attached);
	}
	}

	//Finders comunes 
	@Override
	public long countCategorias() {
		return em.createQuery("SELECT COUNT(o) FROM Categoria o", Long.class).getSingleResult();
	}

	@Override
	public List<Categoria> findAllCategorias() {
        return em.createQuery("SELECT o FROM Categoria o", Categoria.class).getResultList();
	}

	@Override
	public Categoria findCategoria(Integer codigo) {
        if (codigo == null) return null;
        return em.find(Categoria.class, codigo);
	}

	@Override
	public List<Categoria> findCategoriaEntries(int firstResult, int maxResults) {
		return em.createQuery("SELECT o FROM Categoria o", Categoria.class).setFirstResult(firstResult).setMaxResults(maxResults).getResultList();
	}

	
	//Finder Avanzado
    public  TypedQuery<Categoria> findCategoriasByCategorias(Set<Categoria> categorias) {
        if (categorias == null) throw new IllegalArgumentException("The categorias argument is required");
        
        StringBuilder queryBuilder = new StringBuilder("SELECT o FROM Categoria AS o WHERE");
        for (int i = 0; i < categorias.size(); i++) {
            if (i > 0) queryBuilder.append(" AND");
            queryBuilder.append(" :categorias_item").append(i).append(" MEMBER OF o.categorias");
        }
        TypedQuery<Categoria> q = em.createQuery(queryBuilder.toString(), Categoria.class);
        int categoriasIndex = 0;
        for (Categoria _categoria: categorias) {
            q.setParameter("categorias_item" + categoriasIndex++, _categoria);
        }
        return q;
    }
    
    public  TypedQuery<Categoria> findCategoriasByDescripcionEquals(String descripcion) {
        if (descripcion == null || descripcion.length() == 0) throw new IllegalArgumentException("The descripcion argument is required");
        
        TypedQuery<Categoria> q = em.createQuery("SELECT o FROM Categoria AS o WHERE o.descripcion = :descripcion", Categoria.class);
        q.setParameter("descripcion", descripcion);
        return q;
    }
    
    public  TypedQuery<Categoria> findCategoriasByDescripcionIsNotNull() {
        
        TypedQuery<Categoria> q = em.createQuery("SELECT o FROM Categoria AS o WHERE o.descripcion IS NOT NULL", Categoria.class);
        return q;
    }
    
    public  TypedQuery<Categoria> findCategoriasByDescripcionIsNull() {
        
        TypedQuery<Categoria> q = em.createQuery("SELECT o FROM Categoria AS o WHERE o.descripcion IS NULL", Categoria.class);
        return q;
    }
    
    public  TypedQuery<Categoria> findCategoriasByDescripcionLike(String descripcion) {
        if (descripcion == null || descripcion.length() == 0) throw new IllegalArgumentException("The descripcion argument is required");
        descripcion = descripcion.replace('*', '%');
        if (descripcion.charAt(0) != '%') {
            descripcion = "%" + descripcion;
        }
        if (descripcion.charAt(descripcion.length() - 1) != '%') {
            descripcion = descripcion + "%";
        }
        
        TypedQuery<Categoria> q = em.createQuery("SELECT o FROM Categoria AS o WHERE LOWER(o.descripcion) LIKE LOWER(:descripcion)", Categoria.class);
        q.setParameter("descripcion", descripcion);
        return q;
    }
    
    public  TypedQuery<Categoria> findCategoriasByDescripcionNotEquals(String descripcion) {
        if (descripcion == null || descripcion.length() == 0) throw new IllegalArgumentException("The descripcion argument is required");
        
        TypedQuery<Categoria> q = em.createQuery("SELECT o FROM Categoria AS o WHERE o.descripcion != :descripcion", Categoria.class);
        q.setParameter("descripcion", descripcion);
        return q;
    }
    
    public  TypedQuery<Categoria> findCategoriasByNombreEquals(String nombre) {
        if (nombre == null || nombre.length() == 0) throw new IllegalArgumentException("The nombre argument is required");
        
        TypedQuery<Categoria> q = em.createQuery("SELECT o FROM Categoria AS o WHERE o.nombre = :nombre", Categoria.class);
        q.setParameter("nombre", nombre);
        return q;
    }
    
    public  TypedQuery<Categoria> findCategoriasByNombreIsNotNull() {
        
        TypedQuery<Categoria> q = em.createQuery("SELECT o FROM Categoria AS o WHERE o.nombre IS NOT NULL", Categoria.class);
        return q;
    }
    
    public  TypedQuery<Categoria> findCategoriasByNombreIsNull() {
        
        TypedQuery<Categoria> q = em.createQuery("SELECT o FROM Categoria AS o WHERE o.nombre IS NULL", Categoria.class);
        return q;
    }
    
    public  TypedQuery<Categoria> findCategoriasByNombreLike(String nombre) {
        if (nombre == null || nombre.length() == 0) throw new IllegalArgumentException("The nombre argument is required");
        nombre = nombre.replace('*', '%');
        if (nombre.charAt(0) != '%') {
            nombre = "%" + nombre;
        }
        if (nombre.charAt(nombre.length() - 1) != '%') {
            nombre = nombre + "%";
        }
        
        TypedQuery<Categoria> q = em.createQuery("SELECT o FROM Categoria AS o WHERE LOWER(o.nombre) LIKE LOWER(:nombre)", Categoria.class);
        q.setParameter("nombre", nombre);
        return q;
    }
    
    public  TypedQuery<Categoria> findCategoriasByNombreNotEquals(String nombre) {
        if (nombre == null || nombre.length() == 0) throw new IllegalArgumentException("The nombre argument is required");
        
        TypedQuery<Categoria> q = em.createQuery("SELECT o FROM Categoria AS o WHERE o.nombre != :nombre", Categoria.class);
        q.setParameter("nombre", nombre);
        return q;
    }
    
    public  TypedQuery<Categoria> findCategoriasByPadre(Categoria padre) {
        if (padre == null) throw new IllegalArgumentException("The padre argument is required");
        
        TypedQuery<Categoria> q = em.createQuery("SELECT o FROM Categoria AS o WHERE o.padre = :padre", Categoria.class);
        q.setParameter("padre", padre);
        return q;
    }
    
    public  TypedQuery<Categoria> findCategoriasByPublicacions(Set<Publicacion> publicacions) {
        if (publicacions == null) throw new IllegalArgumentException("The publicacions argument is required");
        
        StringBuilder queryBuilder = new StringBuilder("SELECT o FROM Categoria AS o WHERE");
        for (int i = 0; i < publicacions.size(); i++) {
            if (i > 0) queryBuilder.append(" AND");
            queryBuilder.append(" :publicacions_item").append(i).append(" MEMBER OF o.publicacions");
        }
        TypedQuery<Categoria> q = em.createQuery(queryBuilder.toString(), Categoria.class);
        int publicacionsIndex = 0;
        for (Publicacion _publicacion: publicacions) {
            q.setParameter("publicacions_item" + publicacionsIndex++, _publicacion);
        }
        return q;
    }
    


}
